home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / filesy~1 / mfs609s.zoo / minixfs / hdio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-25  |  11.2 KB  |  513 lines

  1. #include "pun.h"
  2. #include "xhdi.h"
  3.  
  4. #include <string.h>
  5.  
  6. #ifdef MFS_XFS
  7. #include "minixfs.h"
  8. #include "global.h"
  9. #define XRWABS RWABS
  10. #define DWARN(mes,drive) ALERT("Drive %c: " mes,drive)
  11. #else
  12. #define DWARN(mes,drive) fprintf(stderr,"Drive %c: " mes "\n",drive)
  13. #define ALERT(x)     fprintf(stderr,x "\n")
  14. #define NEED_SUPER
  15. #define RWABS Rwabs
  16. #define Kmalloc malloc
  17. #define Kfree free
  18. #define GETBPB Getbpb
  19. #include <osbind.h>
  20. #include <alloc.h>
  21. #include <stdio.h>
  22. #include "hdio.h"
  23.  
  24. #define XRWABS(a,b,c,d,e,f) \
  25. trap_13_wwlwwwl((short)(0x04),(short)(a),(long)(b),(short)(c),(short)(d)\
  26. ,(short)(e),(long)(f) )
  27.  
  28. #define trap_13_wwlwwwl(n, a, b, c, d, e, f)                \
  29. ({                                    \
  30.     register long retvalue __asm__("d0");                \
  31.     volatile short _a = (volatile short)(a);            \
  32.     volatile long  _b = (volatile long) (b);            \
  33.     volatile short _c = (volatile short)(c);            \
  34.     volatile short _d = (volatile short)(d);            \
  35.     volatile short _e = (volatile short)(e);            \
  36.     volatile long  _f = (volatile long) (f);            \
  37.                                         \
  38.     __asm__ volatile                        \
  39.     ("\
  40.         movl    %5,sp@-; \
  41.         movw    %4,sp@-; \
  42.         movw    %3,sp@-; \
  43.         movw    %2,sp@-; \
  44.         movl    %1,sp@-; \
  45.         movw    %0,sp@-    "                    \
  46.     :                          /* outputs */    \
  47.     : "r"(_a), "r"(_b), "r"(_c), "r"(_d), "r"(_e), "r"(_f) /* inputs  */ \
  48.     );                                \
  49.                                     \
  50.     __asm__ volatile                        \
  51.     ("\
  52.         movw    %1,sp@-; \
  53.         trap    #13;    \
  54.         addw    #18,sp "                    \
  55.     : "=r"(retvalue)            /* outputs */        \
  56.     : "g"(n)                /* inputs  */        \
  57.     : "d0", "d1", "d2", "a0", "a1", "a2"    /* clobbered regs */    \
  58.     );                                \
  59.     retvalue;                            \
  60. })
  61.  
  62. #endif
  63.  
  64. /* List of error codes for get_hddinf */
  65.  
  66. char *hdd_err[] = { 
  67. "OK",
  68. "Bad BPB on floppy drive",
  69. "Need drive A-P for PUN_INFO",
  70. "Invalid or no PUN_INFO structure",
  71. "Invalid drive",
  72. "Physical mode disabled for ICD software",
  73. "Physical lrecno error",
  74. "XHInqDev2 failed (old XHDI version?) and bad BPB",
  75. "XHInqDev failed",
  76. "Unrecognised partition id",
  77. "XHInqTarget failed",
  78. "Unsupported physical sector size",
  79. "Invalid partition start (zero BPB?)" 
  80. "ICD software too old to fix"};
  81.  
  82.  
  83. /*
  84.  * Hard disk info. This is a general purpose routine to handle minixfs' needs
  85.  * for hard disks. If this function returns non-zero then the partition 
  86.  * cannot be accessed. XHDI and pun_info are used to get partition info.
  87.  * The structure 'hdinf' is filled in as approproiate.
  88.  *
  89.  * If this looks awful then that's because it *is*.
  90.  */
  91.  
  92. static char rno_xhdi,try_xhdi;
  93. static char try_lrecno,rno_lrecno;
  94. static char try_plrecno,rno_plrecno;
  95.  
  96. char is_icd =-1 ;
  97. unsigned char *cache_icd;
  98.  
  99. int get_hddinf(drive,hdinf,flag)
  100. int drive;
  101. struct hdinfo *hdinf;
  102. char flag;
  103. {
  104.     long ret;
  105. #ifdef NEED_SUPER
  106.     long tstack;
  107.     tstack=Super(0l);
  108.     if(!((*(long *)0x4c2) & (1l<<drive))) return 4;
  109. #endif
  110.     ret = _get_hddinf(drive,hdinf,flag);
  111. #ifdef NEED_SUPER
  112.     Super(tstack);
  113. #endif
  114.     return ret;
  115. }
  116.  
  117. int _get_hddinf(drive,hdinf,flag)
  118. int drive;
  119. struct hdinfo *hdinf; 
  120. char flag;
  121. {
  122.     _BPB *bpb;
  123.  
  124.     hdinf->major=drive;    /* May get overwritten later */
  125.  
  126.     hdinf->drive=drive;
  127.  
  128.     init_icd();
  129.  
  130.     bpb=GETBPB(drive); 
  131.     if( flag ) bpb=0;
  132.  
  133.  
  134.     /* Step 1: if bpb OK and sector size 512 bytes or 1K we may get away
  135.      * with normal Rwabs.
  136.      */
  137.  
  138.     if( !bpb || (bpb->recsiz!=512 && bpb->recsiz!=1024) )
  139.     {
  140.         long tsecsiz;
  141.         char mpid[4];
  142.  
  143.         /* OK can't use normal Rwabs: try XHDI or pun_info */
  144.  
  145.         /* Bypass this rubbish for floppies */
  146.         if(drive < 2 ) return 1;
  147.  
  148.         /* Try and get info from pun_inf structure */
  149.         if( no_xhdi() )
  150.         {
  151.             struct pun_info *pinf;
  152.             if(drive >= MAXUNITS) return 2;
  153.             if(!(*(long *)0x516)) return 3;
  154.             pinf=PUN_PTR;
  155.             if(!pinf || (PUN_VALID & pinf->pun[drive]) ) return 4;
  156.             hdinf->scsiz = 1;
  157.  
  158.             if(is_icd)
  159. #ifdef NO_ICD_PHYS
  160.                 return 5;
  161. #else
  162.             {
  163.                 if(is_icd==2) return 13;
  164.                 hdinf->start = pinf->partition_start[drive+4];
  165.             }
  166. #endif
  167.             else hdinf->start = pinf->partition_start[drive];
  168.  
  169.             if(!hdinf->start) return 12;
  170.  
  171.             hdinf->size = 0;
  172.             hdinf->minor = pinf->pun[drive];
  173.             if(is_icd) hdinf->major=drive;
  174.             else hdinf->major = (hdinf->minor & PUN_DEV) +2;
  175.             hdinf->rwmode = RW_PHYS;
  176.             /* We want to access at least first few sectors */
  177.             if(hdinf->start > 0xfff0)
  178.             {
  179.                 if(no_plrecno(hdinf->major)) return 6;
  180.                 else hdinf->rwmode |= RW_LRECNO;
  181.             }
  182.             return 0;
  183.         }
  184.  
  185.         hdinf->rwmode = RW_XHDI | RW_LRECNO;
  186.  
  187.         /* Hmmmm Getbpb failed or bad secsize: see what XHDI can do */
  188.  
  189.         if( XHInqDev2(drive,&hdinf->major,&hdinf->minor,&hdinf->start,
  190.                               0,&hdinf->size,mpid) )
  191.         {
  192.             if(!bpb && !flag ) return 7;
  193.             if( XHInqDev(drive,&hdinf->major,&hdinf->minor,
  194.                             &hdinf->start,0) ) return 8;
  195.             hdinf->size=0;
  196.         }
  197.         else if(!bpb && strcmp(mpid,"RAW") && strcmp(mpid,"MIX")
  198.                && strcmp(mpid,"BGM") && strcmp(mpid,"GEM") ) return 9;
  199.  
  200.         /* Get physical sector size */
  201.         if( XHInqTarget(hdinf->major,hdinf->minor,&tsecsiz,0,0) )
  202.                                       return 10;
  203.  
  204.         if(tsecsiz==512) hdinf->scsiz=1;
  205.         else 
  206.         {
  207.             if(tsecsiz==1024) hdinf->scsiz=0;
  208.             else return 11;
  209.         }
  210.         return 0;
  211.     }
  212.     if(bpb->recsiz==512) hdinf->scsiz=1;
  213.     else hdinf->scsiz=0;
  214.     hdinf->size=0;
  215.     hdinf->rwmode = RW_NORMAL;
  216.     return 0;
  217. }
  218.  
  219. /* Special kludge for icd software. This software accesses far too many sectors
  220.  * when physical mode I/O is attempted on sectors bigger than 0xffff with the
  221.  * cache on. What we do
  222.  * is to:
  223.  * 1. Test for ICD software.
  224.  * 2. Set a pointer to the 'cache flag'.
  225.  * Return values:
  226.  * 0 Non ICD software or PUN_INFO problem.
  227.  * 1 Probably non ICD host adaptor used with ICD software.
  228.  * 2 ICD software doesn't have a 'cache flag' (probably too old).
  229.  * 3 Probably kludgable (OK).
  230.  * Only '2' is fatal.
  231.  */
  232.  
  233.  
  234. int init_icd()
  235. {
  236.     char *icd_magic;    
  237.     if(is_icd!=-1) return is_icd;
  238.     if(!*((long *)0x516)) return is_icd=0;
  239.     icd_magic=((char *)PUN_PTR)-6;
  240.     if(strncmp(icd_magic,"ICDB",4)) return is_icd=0;
  241.     else
  242.     {
  243.         char *icdh_magic;
  244.         if( icd_magic[5] < 0x50 ) return is_icd=2;
  245.         icdh_magic=*((char ** )(icd_magic-4));
  246.         if(strncmp(icdh_magic,"ICDH",4)) return is_icd=1;
  247.         if( icdh_magic[4] < 0x50 ) return is_icd=2;
  248.         cache_icd = (unsigned char *)(icdh_magic+6);
  249.         return is_icd=3;
  250.     }
  251. }
  252.  
  253. /* This function is called after get_hddinf and is used to finalise the
  254.  * accessibility of a partition. The 'size' parameter is the size of the
  255.  * partition in K; this info will typically come from the super block of
  256.  * a filesystem. 
  257.  * Return values:
  258.  * 0    OK
  259.  * 1    Partition inaccessible.
  260.  */
  261.  
  262. int set_lrecno(hdinf,size)
  263. struct hdinfo *hdinf;
  264. long size;
  265. {
  266.     long tsize;
  267.     tsize=size;
  268.     if(hdinf->scsiz) tsize <<=1;
  269.     if( ( (hdinf->rwmode & RW_MODE) == RW_XHDI) && hdinf->size
  270.                               && (hdinf->size < tsize) )
  271.     {
  272.         DWARN("Filesystem size bigger than partition size!",
  273.                                 hdinf->drive);
  274.     }
  275.     else hdinf->size = tsize;
  276.  
  277.     hdinf->rwmode |= RW_CHECK;
  278.  
  279.     if(hdinf->rwmode & RW_LRECNO) return 0;
  280.  
  281.     switch(hdinf->rwmode & RW_MODE)
  282.     {
  283.         case RW_NORMAL:
  284.         if(tsize < 0xffff)
  285.         {
  286.             char *tmp_buf;
  287.             tmp_buf=Kmalloc(1024);
  288.             if(!tmp_buf) return 1;
  289.             /* Try to read last block */
  290.             if(!block_rwabs(2,tmp_buf,1,size-1,hdinf)) 
  291.             {
  292.                 Kfree(tmp_buf);
  293.                 return 0;
  294.             }
  295.             Kfree(tmp_buf);
  296.         }
  297.  
  298.         if( tsize < 0xffff || no_lrecno(hdinf->major) )
  299.         {
  300.         /* Bad lrecno or access error try physical mode access */
  301.             int drive;
  302.             drive = hdinf->major;
  303.             if(get_hddinf(drive,hdinf,1)) return 1;
  304.             else return (set_lrecno(hdinf,size));
  305.         }
  306.         else hdinf->rwmode |= RW_LRECNO;
  307.         return 0;
  308.  
  309.         case RW_PHYS:
  310.         if(tsize+hdinf->start >= 0xfffe)
  311.         {
  312.             if(no_plrecno(hdinf->major)) return 1;
  313.             hdinf->size = tsize;
  314.             hdinf->rwmode |= RW_LRECNO;
  315.         }
  316.         return 0;
  317.     }
  318.  
  319.     return 1;    /* This can't happen */
  320. }
  321.  
  322. /* Test for 'lrecno' parameter on drive 'drive': mode' is RWABS mode to use 
  323.  * (2=logical,10=physical).
  324.  * Return values:
  325.  * 0 OK
  326.  * 1 Read error.
  327.  * 2 No lrecno recognised.
  328.  * 3 Error reading large sector number (possibly OK if partition too small).
  329.  * 4 Wraparound bug present.
  330.  * 5 Allocation error.
  331.  */
  332.  
  333. int test_lrecno(drive,mode)
  334. int drive;
  335. int mode;
  336. {
  337.     char *block_buf1,*block_buf2;
  338.     int size;
  339.     _BPB *bpb;
  340.     bpb=Getbpb(drive);
  341.     if( (mode & 8) || !bpb ) size=1024;
  342.     else size=bpb->recsiz;
  343.  
  344.     block_buf1=Kmalloc(size<<1);
  345.     block_buf2=block_buf1+size;
  346.     bzero(block_buf1,size<<1);
  347.  
  348.     if(!block_buf1) return 5;
  349.  
  350.     /* read in boot sector */
  351.     if(RWABS(mode,block_buf1,1,0,drive)) 
  352.     {
  353.         Kfree(block_buf1);
  354.         return 1;
  355.     }
  356.  
  357.     /* read it in with lrecno */    
  358.     if( XRWABS(mode,block_buf2,1,-1,drive,0l) ) 
  359.     {
  360.         Kfree(block_buf1);
  361.         return 2;
  362.     }
  363.  
  364.     /* Compare the two */
  365.     if(bcmp(block_buf1,block_buf2,size))
  366.     {
  367.         Kfree(block_buf1);
  368.         return 2;
  369.     }
  370.  
  371.     /* read in next sector with lrecno */
  372.     if(XRWABS(mode,block_buf2,1,-1,drive,1l))
  373.     {
  374.         Kfree(block_buf1);
  375.         return 1;
  376.     }
  377.  
  378.     /* compare the two */
  379.     if(!bcmp(block_buf1,block_buf2,size))
  380.     {
  381.         Kfree(block_buf1);
  382.         return 2;
  383.     }
  384.  
  385.     /* Check for lrecno bug, this causes the upper word of a long sector
  386.      * number to be ignored. Read in sector 0 and 0x10000, if the bug is
  387.      * present then these will be identical.
  388.      */
  389.     bzero(block_buf2,size);
  390.  
  391.     if(XRWABS(mode,block_buf2,1,-1,drive,0x10000l))
  392.     {
  393.         Kfree(block_buf1);
  394.         return 3;
  395.     }
  396.     else if(!bcmp(block_buf1,block_buf2,size))
  397.     {
  398.         Kfree(block_buf1);
  399.         return 4;
  400.     }
  401.  
  402.     Kfree(block_buf1);
  403.     return 0;
  404.  
  405. }
  406.  
  407. int no_lrecno(drv)
  408. int drv;
  409. {
  410.     if( !try_lrecno )
  411.     {
  412.         rno_lrecno = test_lrecno(drv,2) ;
  413.         try_lrecno = 1;
  414.     }
  415.     return rno_lrecno;
  416. }
  417.  
  418. int no_plrecno(drv)
  419. int drv;
  420. {
  421. #ifdef NO_ICD_PHYS
  422.     if(is_icd) return 1;
  423. #endif
  424.  
  425.     if( !try_plrecno ) 
  426.     {
  427.         unsigned char cache_tmp=0;
  428.         try_plrecno = 1;
  429.         if(cache_icd)
  430.         {
  431.             cache_tmp=*cache_icd;
  432.             *cache_icd=0;
  433.         }
  434.         rno_plrecno = test_lrecno(drv,10) ;
  435.         if(cache_icd) *cache_icd=cache_tmp;
  436.     }
  437.     return rno_plrecno;
  438. }
  439.  
  440. int no_xhdi()
  441. {
  442.     if( !try_xhdi ) 
  443.     {
  444.         if( !XHGetVersion() ) rno_xhdi=1;
  445.         try_xhdi=1;
  446.     }
  447.     return rno_xhdi;
  448. }
  449.  
  450. /* 
  451.  * This is (finally!) the I/O function hdinf uses. It reads/writes in 1K chunks
  452.  * and calls the relevant functions according to the hdinf structure.
  453.  */
  454.  
  455. long block_rwabs(rw,buf,num,recno,hdinf)
  456. int rw;
  457. void *buf;
  458. unsigned num;
  459. long recno;
  460. struct hdinfo *hdinf;
  461. {
  462.     unsigned char cache_tmp=0;
  463.     long ret;
  464.  
  465.     if( hdinf->scsiz )
  466.     {
  467.         recno <<=1;
  468.         num <<=1;
  469.     }
  470.  
  471.     if( (hdinf->rwmode & RW_CHECK) && (recno+num > hdinf->size) )
  472.     {
  473.         DWARN("Attempted access outside partition",hdinf->drive);
  474.         return -1;
  475.     }
  476.  
  477.     switch(hdinf->rwmode & (RW_MODE|RW_LRECNO))
  478.     {
  479.         case RW_NORMAL:
  480.         return RWABS(rw,buf,num,(unsigned)recno,hdinf->major);
  481.  
  482.         case RW_NORMAL | RW_LRECNO:
  483.         return XRWABS(rw,buf,num,-1,hdinf->major,recno);
  484.  
  485.         case RW_PHYS:
  486.         if(cache_icd)
  487.         {
  488.             cache_tmp=*cache_icd;
  489.             *cache_icd=0;
  490.         }
  491.         ret = RWABS(rw | 8,buf,num,(unsigned)(recno+hdinf->start),
  492.                                   hdinf->major);
  493.         if(cache_icd) *cache_icd=cache_tmp;
  494.         return ret;
  495.  
  496.         case RW_PHYS | RW_LRECNO:
  497.         if(cache_icd)
  498.         {
  499.             cache_tmp=*cache_icd;
  500.             *cache_icd=0;
  501.         }
  502.         ret = XRWABS(rw | 8,buf,num,-1,hdinf->major,
  503.                                 recno+hdinf->start);
  504.         if(cache_icd) *cache_icd=cache_tmp;
  505.         return ret;
  506.  
  507.         case RW_XHDI | RW_LRECNO:
  508.         return XHReadWrite(hdinf->major,hdinf->minor,rw,
  509.                             recno+hdinf->start,num,buf);
  510.     }
  511.     return 1;    /* This can't happen ! */
  512. }
  513.